package com.bycx.dingxinlc.service.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.bycx.core.constant.WXPayConstant;
import com.bycx.core.exception.BusinessException;
import com.bycx.core.startup.AppConfig;
import com.bycx.core.util.MapUtil;
import com.bycx.core.util.SessionUtil;
import com.bycx.core.util.SnowflakeIdUtil;
import com.bycx.core.util.StringUtils;
import com.bycx.dingxinlc.mapper.TCustPayInfoHisMapper;
import com.bycx.dingxinlc.mapper.TCustPayInfoMapper;
import com.bycx.dingxinlc.model.TCustPayInfo;
import com.bycx.dingxinlc.service.WechatPayService;
import com.bycx.dingxinlc.wxpay.WXPayHelper;
import com.bycx.wechat.util.WeChatSessionUtil;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;

/**
 * 微信支付信息
 * 
 * @ClassName: WechatPayServiceImpl
 * @author Allen
 * @date 2018年4月17日
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class WechatPayServiceImpl implements WechatPayService {
	private Log log = LogFactory.getLog(WechatPayServiceImpl.class);

	@Autowired
	private TCustPayInfoMapper tCustPayInfoMapper;
	@Autowired
	private TCustPayInfoHisMapper tCustPayInfoHisMapper;
	@Autowired
	private WXPayHelper wXPayHelper;

	@Override
	public Map<String, String> preOrder(BigDecimal money) throws Exception {
		log.info("========== 生成预付订单-开始 ===========>>");

		// 数据准备
		String id = StringUtils.getUUID();
		String orderNo = String.valueOf(SnowflakeIdUtil.getWechatTradeNo());// 通过雪花算法生成内部订单号
		String openId = WeChatSessionUtil.getOpenId();
		String phoneNo = WeChatSessionUtil.getCustLoginInfo().getPhoneNo();
		Date now = new Date();

		// 生成支付信息
		TCustPayInfo params = new TCustPayInfo();
		params.setId(id);
		params.setOrderNo(orderNo);
		params.setOpenId(openId);
		params.setPhoneNo(phoneNo);
		params.setOrderAmt(money);
		params.setOrderTime(now);
		params.setStatus(WXPayConstant.WX_PAY_ORDER_STATUS_1);
		params.setCreateTime(now);
		tCustPayInfoMapper.insertCustPayInfo(params);
		tCustPayInfoHisMapper.insertCustPayInfoHis(params);
		log.info("=====插入支付信息：" + JSONObject.toJSONString(params));

		// 调用微信统一订单接口
		// 参数准备
		String appid = AppConfig.get("wx_appid");
		String total_fee = String.valueOf(money.multiply(new BigDecimal(100)).intValue());
		String spbill_create_ip = SessionUtil.getClientIP();
		String notify_url = SessionUtil.getBasePath() + "/wechat/pay/notify";
		String time_start = new SimpleDateFormat("yyyyMMddHHmmss").format(now);
		// 参数装配
		Map<String, String> data = new HashMap<>();
		data.put("device_info", "WEB");
		data.put("body", "鼎新联创-会员充值");
		data.put("out_trade_no", orderNo);
		data.put("fee_type", "CNY");
		data.put("total_fee", total_fee);
		data.put("spbill_create_ip", spbill_create_ip);
		data.put("time_start", time_start);
		data.put("notify_url", notify_url);
		data.put("trade_type", "JSAPI");
		data.put("limit_pay", "no_credit");
		data.put("openid", openId);
		MapUtil.removeNullValue(data);// 由于WXPay SDK中存在未进行null值判断的bug，因此此处需要提前清洗
		log.info("=====远程调用post主要数据：" + JSONObject.toJSONString(data));
		// 提交请求
		Map<String, String> res = wXPayHelper.unifiedOrder(data);
		log.info("=====远程调用结果：" + JSONObject.toJSONString(res));
		// 结果处理
		String return_code = res.get("return_code");
		if (!WXPayConstants.SUCCESS.equals(return_code)) {
			String return_msg = res.get("return_msg");
			log.error("统一下单接口调用失败！[return_code=" + return_code + ", return_msg=" + return_msg + "]");
			throw new BusinessException("下单失败！");
		}
		String result_code = res.get("result_code");
		if (!WXPayConstants.SUCCESS.equals(result_code)) {
			String err_code = res.get("err_code");
			String err_code_des = res.get("err_code_des");
			log.error("统一下单业务失败！[result_code=" + result_code + ", err_code=" + err_code + ", err_code_des=" + err_code_des + "]");
			throw new BusinessException("下单失败！");
		}

		String prepay_id = res.get("prepay_id");
		log.info("统一下单接口调用成功！[prepay_id=" + prepay_id + "]");

		// 生成前端需要的数据
		Map<String, String> returnMap = new HashMap<String, String>();
		returnMap.put("appId", appid);
		returnMap.put("timeStamp", String.valueOf(now.getTime() / 1000));
		returnMap.put("nonceStr", id);
		returnMap.put("package", "prepay_id=" + prepay_id);
		returnMap.put("signType", WXPayConstants.MD5);
		String paySign = WXPayUtil.generateSignature(returnMap, AppConfig.get("wx_pay_key"));
		returnMap.put("paySign", paySign);
		log.info("=====要返回给前端的数据：" + JSONObject.toJSONString(returnMap));

		log.info("<<========== 生成预付订单-结束 ===========");

		return returnMap;
	}

	@Override
	public void updateOrderInfo(Map<String, String> map) throws Exception {
		log.info("========== 微信支付回调信息处理-开始 ===========>>");

		// 数据获取
		String result_code = map.get("result_code");
		String out_trade_no = map.get("out_trade_no");
		String time_end = map.get("time_end");
		String transaction_id = map.get("transaction_id");
		String err_code = map.get("err_code");
		String err_code_des = map.get("err_code_des");

		Date now = new Date();
		SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmmss");

		// 处理业务数据
		TCustPayInfo params = new TCustPayInfo();
		params.setOrderNo(out_trade_no);
		params.setTransactionId(transaction_id);
		params.setReturnMsg("[" + err_code + "]" + err_code_des);
		params.setUpdateTime(now);
		// 失败
		if (!WXPayConstants.SUCCESS.equals(result_code)) {
			params.setStatus(WXPayConstant.WX_PAY_ORDER_STATUS_3);
			if (StringUtils.isNotEmpty(time_end)) {
				params.setPayTime(sdf1.parse(time_end));
			}
		}
		// 成功
		else {
			params.setStatus(WXPayConstant.WX_PAY_ORDER_STATUS_2);
			params.setPayTime(sdf1.parse(time_end));
		}
		// 更新info表
		tCustPayInfoMapper.updateByOrderNo(params);
		log.info("=====更新支付信息，参数：" + JSONObject.toJSONString(params));
		// 记录历史
		TCustPayInfo newPayInfo = this.queryPayInfoByOrderNo(out_trade_no);
		if (newPayInfo != null) {
			newPayInfo.setId(StringUtils.getUUID());
			newPayInfo.setCreateTime(now);
			newPayInfo.setUpdateTime(null);
			tCustPayInfoHisMapper.insertCustPayInfoHis(newPayInfo);
			log.info("=====新增支付历史信息，参数：" + JSONObject.toJSONString(newPayInfo));
		}

		log.info("<<========== 微信支付回调信息处理-结束 ===========");
	}

	@Override
	public TCustPayInfo queryPayInfoByOrderNo(String orderNo) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("orderNo", orderNo);
		return tCustPayInfoMapper.get(params);
	}
}
